package com.medibooking.gwt.client.calendar;

import java.util.Date;

import com.google.gwt.event.shared.EventBus;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.medibooking.gwt.client.calendar.events.CalendarGridRenderedEvent;
import com.medibooking.gwt.client.calendar.events.CalendarGridRenderedEventHandler;
import com.medibooking.gwt.client.calendar.events.DateHeaderRenderedEvent;
import com.medibooking.gwt.client.calendar.events.DateHeaderRenderedEventHandler;
import com.medibooking.gwt.client.calendar.views.CalendarView;
import com.medibooking.gwt.client.calendar.widgets.CurrentDateWidget;
import com.medibooking.gwt.client.menu.CalendarPeriodNavigation;
import com.medibooking.gwt.client.menu.events.CalendarPeriodChangeEvent;
import com.medibooking.gwt.client.menu.events.CalendarPeriodChangeHandler;
import com.medibooking.gwt.client.menu.events.CalendarPeriodNavigationEvent;
import com.medibooking.gwt.client.menu.events.CalendarPeriodNavigationEventHandler;
import com.medibooking.gwt.client.menu.events.TimeSlotChangeEvent;
import com.medibooking.gwt.client.menu.events.TimeSlotChangeEventHandler;
import com.medibooking.gwt.client.util.CalendarUtils;
import com.medibooking.gwt.client.util.DateFormatter;

@Singleton
public class CalendarManager {

    private CalendarState  calendarStateManager;
    private EventBus              eventBus;
    private CalendarView          calendarView;
    private CurrentDateWidget currentDateInfoWidget;

    /**
     * Constructor
     * @param currentDateInfoWidget
     * @param calendarStateManager
     * @param eventBus
     * @param calendarView
     */
    @Inject
    public CalendarManager(CurrentDateWidget currentDateInfoWidget, CalendarState calendarStateManager, EventBus eventBus,
            CalendarView calendarView) {
        this.calendarView = calendarView;
        this.currentDateInfoWidget = currentDateInfoWidget;
        this.calendarStateManager = calendarStateManager;
        this.eventBus = eventBus;
        registerViewsRenderedHandlers();
        
        registerMenuOptionsHandler();

        updateCurrentDateWidget();
    }

    /**
     * Update the date interval in the calendar
     */
    private void updateCurrentDateWidget() {
        Date endDate = CalendarUtils.getDateWithAddedDays(this.calendarStateManager.getEndDate(), -1);
        String text = "";
        if (calendarStateManager.getCalendarPeriod().equals(CalendarPeriod.ONE_DAY)) {
            text = DateFormatter.formatDate(this.calendarStateManager.getStartDate());
        } else {
            text = DateFormatter.formatInterval(this.calendarStateManager.getStartDate(), endDate);
        }

        this.currentDateInfoWidget.updateText(text);
    }

    /**
     * Change the visible period on the calendar
     * @param period
     */
    private void chandeCalendarViewPeriod(CalendarPeriod period) {
        // Update stat
        calendarStateManager.setCalendarPeriod(period);
        switch (period) {
            case ONE_DAY:
                // update startDate for today if the period is one day
                Date today = new Date();
                calendarStateManager.setStartDate(today);
                calendarStateManager.setEndDate(today);

                break;

            case WEEK:
                Date newStartDate = CalendarUtils.getLastMondayDate();

                calendarStateManager.setStartDate(newStartDate);

                calendarStateManager.setEndDate(CalendarUtils.getDateWithAddedDays(newStartDate, calendarStateManager.getCalendarPeriod()
                        .numberOfDays()));

                break;
            case FOUR_DAYS:
                calendarStateManager.setStartDate(new Date());
                calendarStateManager.setEndDate(CalendarUtils.getDateWithAddedDays(new Date(), calendarStateManager.getCalendarPeriod()
                        .numberOfDays()));

                // let the start date be today
                break;
        }

        calendarView.getCalendarGrid().render();
        calendarView.getDateHeaderRow().render();

    }

    /**
     * Register handlers for the menu
     */
    private void registerMenuOptionsHandler() {
        this.eventBus.addHandler(TimeSlotChangeEvent.TYPE, new TimeSlotChangeEventHandler() {

            public void onTimeSlotChanged(TimeSlotChangeEvent event) {
                calendarStateManager.setTimeSlotSize(event.getSlotSize());
                calendarView.getCalendarGrid().render();
            }
        });

        this.eventBus.addHandler(CalendarPeriodChangeEvent.TYPE, new CalendarPeriodChangeHandler() {

            public void onCalendarPeriodChanged(CalendarPeriodChangeEvent event) {
                chandeCalendarViewPeriod(event.getPeriod());
            }
        });

        this.eventBus.addHandler(CalendarPeriodNavigationEvent.TYPE, new CalendarPeriodNavigationEventHandler() {

            public void onCalendarPeriodNavigation(CalendarPeriodNavigationEvent event) {
                // Calculate the next start date
                Date currentStartDate = calendarStateManager.getStartDate();
                int multiplier = event.getCalendarPeriodNavigation().equals(CalendarPeriodNavigation.NEXT_PERIOD) ? 1 : -1;

                calendarStateManager.setStartDate(CalendarUtils.getDateWithAddedDays(currentStartDate, multiplier
                        * calendarStateManager.getCalendarPeriod().numberOfDays()));

                calendarStateManager.setEndDate(CalendarUtils.getDateWithAddedDays(calendarStateManager.getEndDate(), multiplier
                        * calendarStateManager.getCalendarPeriod().numberOfDays()));

                calendarView.getCalendarGrid().markToday();
                calendarView.getDateHeaderRow().render();

            }
        });

    }

   

    /**
     * Register handlers for rendered finished
     */
    private void registerViewsRenderedHandlers() {
        // Register handler for grid rendered
        eventBus.addHandler(CalendarGridRenderedEvent.TYPE, new CalendarGridRenderedEventHandler() {

            public void onCalendarGridRendered(CalendarGridRenderedEvent event) {
                updateCurrentDateWidget();

            }
        });

        // register handler for header rendered
        eventBus.addHandler(DateHeaderRenderedEvent.TYPE, new DateHeaderRenderedEventHandler() {

            public void onDateHeaderRendered(DateHeaderRenderedEvent event) {
                updateCurrentDateWidget();
            }
        });

    }

}
